// ellapse between two TimeFT or two DateTimeFT
// 2023-1025, by hzsong, in lufeng

use super::u3_native::SystemTime;

use super::{b3_datetime::DateTimeFT, a8_micros};

pub type EllapseOnlyTime = super::b2_time::TimeFT; 

/// ellapse between two TimeFT or two DateTimeFT,
/// measure by micros
#[derive(serde::Deserialize, serde::Serialize, Clone, Copy, Default)]
pub struct EllapseFT {
    micros: i64,
    sign: char,
    days: u32,
    only_time: EllapseOnlyTime,
}

impl EllapseFT {
    pub fn new(micros: i64) -> Self {
        let (sign, micros_abs) =  if micros < 0 { ('-', -micros) } else { ('+', micros) };
        let days = (micros_abs / super::a8_micros::MICROS_PER_DAY) as u32;
        let micros_only_time = micros_abs % super::a8_micros::MICROS_PER_DAY;
        let only_time = EllapseOnlyTime::from_secsday_micros(micros_only_time);

        Self { micros, sign, days, only_time }
    }
    pub fn micros(&self) -> i64 {
        self.micros
    }
}
impl EllapseFT {
    /// 不精确
    pub fn to_print_friendly(&self) -> String {
        if self.days > 100 {
            return format!("Ellapse: ~= {}{} days", self.sign, self.days);
        }
        let secs_of_day = self.only_time.secs_of_day();
        if self.days > 0 {
            let days_f64 = self.days as f64 + (secs_of_day as f64 / super::a7_secs::SECS_PER_DAY as f64);
            if self.days > 10 {
                return format!("Ellapse: ~= {}{days_f64:.1} days", self.sign);
            }
            return format!("Ellapse: ~= {}{days_f64:.2} days", self.sign);
        }
        let hours = secs_of_day as f64 / super::a7_secs::SECS_PER_HOUR as f64;
        if hours > 10.0 {
            return format!("Ellapse: ~= {}{hours:.1} hours", self.sign);
        }
        if hours > 1.0 {
            return format!("Ellapse: ~= {}{hours:.2} hours", self.sign);
        }
        let miniutes = secs_of_day as f64 / super::a7_secs::SECS_PER_MINUTE as f64;
        if miniutes > 10.0 {
            return format!("Ellapse: ~= {}{miniutes:.1} miniutes", self.sign);
        }
        if miniutes > 1.0 {
            return format!("Ellapse: ~= {}{miniutes:.2} miniutes", self.sign);
        }
        if secs_of_day > 10 {
            return format!("Ellapse: ~= {}{secs_of_day} seconds", self.sign);
        }

        self.only_time.to_print_sio()

    }
    /// 精确
    pub fn to_print_exactly(&self) -> String {
        if self.days > 0 {
            return format!("Ellapse: {}{} days {}", self.sign, self.days, self.only_time.to_print_hmsio());
        }
        let hours = self.only_time.hour();
        if hours > 0 {
            return format!("Ellapse: {}{}", self.sign, self.only_time.to_print_hmsio());
        }
        let minutes = self.only_time.minute();
        if minutes > 0 {
            return format!("Ellapse: {}{}", self.sign, self.only_time.to_print_hmsio());
        }
        self.only_time.to_print_sio()
    }
}




/// 微秒数
pub struct TicksFT {
    system_time_start: SystemTime,
    dt_start: DateTimeFT,
    list_name_micros: Vec<(String, i64)>,
    micros_total: i64,
}

impl TicksFT {
    pub fn new() -> Self{
        let (system_time_start, dt_start) = super::a6_timestamp::now();
        TicksFT {
            system_time_start,
            dt_start,
            list_name_micros: vec![],
            micros_total: 0,
        }
    }
    pub fn to_print(&self) -> String {
        let 开始时间 = self.dt_start.to_print();
        let mut buf = format!("TicksFT: 开始时间={开始时间}, 总耗时={} 微秒, 总计时次数={}\n", a8_micros::format_micros(self.micros_total), self.list_name_micros.len());

        let mut micros_total_sub = 0;
        for (name, micros) in self.list_name_micros.iter() {
            micros_total_sub += *micros;
            buf.push_str(&format!("\t{name}\t本次 {} 微秒\t总计 {} 微秒\n", a8_micros::format_micros(*micros), a8_micros::format_micros(micros_total_sub)));
        }

        buf
    }
}

impl TicksFT {
    pub fn tick_micros(&mut self, name: &str) -> i64 {
        let micros_当前总耗时_上一次 = self.micros_total;
        self.micros_total = self.system_time_start.elapsed().unwrap_or_default().as_micros() as i64;
        let 本次耗时 = self.micros_total - micros_当前总耗时_上一次;
        self.list_name_micros.push((name.to_string(), 本次耗时));

        本次耗时
    }

    pub fn micros_total(&self) -> i64 {
        self.micros_total
    }
}

// impl TicksFT {
//     pub fn to_print(&self) -> String {
//         let 总耗时 = if self.micros_total < 10_000 {
//             format!("{} 微秒", self.micros_total)
//         } else if self.micros_total < 10_000_000 {
//             format!("{} 毫秒", self.micros_total / 1_000)
//         } else {
//             format!("{} 秒", self.micros_total / 1_000_000)
//         };
//         let mut buf = format!("总耗时={总耗时}: ");
//         for (名称, 本次耗时) in self.list_name_micros.iter() {
//             buf.push_str(&format!("{本次耗时} ({名称}) + "));
//         }

//         buf
//     }

// }

#[test]
fn test_ticksft() {
    let mut ticks = TicksFT::new();
    for i in 1..10 {
        std::thread::sleep(std::time::Duration::from_millis(i * 100));
        _ = ticks.tick_micros(&format!("计时 {i}"));
    }
    println!("{}", ticks.to_print())
}